/****************************************************************************
**
** Copyright (C) 2013 Ernesto Barragan <ernestus at gmail dot com>
** Based on code by the Qt project:
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
**
** GNU General Public License Usage
** This file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
****************************************************************************/

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "console.h"
#include "settingsdialog.h"
#include "fontchooser.h"

#include <QMessageBox>
#include <QFontDialog>
#include <QtSerialPort/QSerialPort>
#include "serialportsettings.h"
#include "aboutdialog.h"
#include "sequenceseditor.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_serialPortTextIndicator( new QLabel() ),
    m_serialPortGraphicIndicator( new QLabel() ),
    m_numericInputDialog( new NumericInputDialog )
{

    QCoreApplication::setOrganizationName("Telekommand Ltd.");
    QCoreApplication::setOrganizationDomain("telekommand.com");
    QCoreApplication::setApplicationName("VisualTerm");

    //QSettings settings;
    ui->setupUi(this);
    m_console = new Console;
    m_console->setEnabled(false);
    setCentralWidget(m_console);

    m_serialPort = new QSerialPort(this);

    m_settingsDialog = new SerialSettingsDialog;

    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
    ui->actionQuit->setEnabled(true);
    ui->actionConfigure->setEnabled(true);

    initActionsConnections();

    connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this,
            SLOT(handleError(QSerialPort::SerialPortError)));


    connect(m_serialPort, SIGNAL(readyRead()), this, SLOT(readSerialData()));

    connect(m_console, SIGNAL(getData(QByteArray)), this, SLOT(writeData(QByteArray)));

#ifdef Q_OS_WIN
    setWindowTitle( tr("VisualTerm for Windows") ) ;
#elif defined( Q_OS_UNIX )
    setWindowTitle( tr("VisualTerm for Unix") ) ;
#endif
    m_serialPortTextIndicator->setText( m_serialPort->portName() );
    ui->statusBar->addPermanentWidget( m_serialPortTextIndicator ) ;
    m_serialPortGraphicIndicator->setPixmap(QPixmap(QString::fromUtf8("://images/yellowStone24.png")));
    ui->statusBar->addPermanentWidget( m_serialPortGraphicIndicator ) ;
    m_console->setFocus() ;
}

MainWindow::~MainWindow()
{
    delete m_settingsDialog;
    delete ui;
}

void MainWindow::openSerialPort()
{
    SerialPortSettings p ;
    m_serialPort->setPortName(p.device);
    if (m_serialPort->open(QIODevice::ReadWrite))
    {
        if (p.applyToPort(*m_serialPort))
        {

            m_console->setEnabled(true);
            m_console->setLocalEchoEnabled(p.localEchoEnabled);
            ui->actionConnect->setEnabled(false);
            ui->actionDisconnect->setEnabled(true);
            ui->actionConfigure->setEnabled(false);
#if 0 //@fixme
            ui->statusBar->showMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
                                       .arg(p.device).arg(p.stringBaudRate).arg(p.stringDataBits)
                                       .arg(p.stringParity).arg(p.stringStopBits).arg(p.stringFlowControl));
#endif
            m_serialPortGraphicIndicator->setPixmap(QPixmap(QString::fromUtf8("://images/greenStone24.png")));
        }
        else
        {
            m_serialPort->close();
            QMessageBox::critical(this, tr("Error"), m_serialPort->errorString());
            m_serialPortGraphicIndicator->setPixmap(QPixmap(QString::fromUtf8("://images/redStone24.png")));
            ui->statusBar->showMessage(tr("Open error"));
        }
    }
    else
    {
        QMessageBox::critical(this, tr("Error"), m_serialPort->errorString());
        ui->statusBar->showMessage(tr("Configure error"));
        m_serialPortGraphicIndicator->setPixmap(QPixmap(QString::fromUtf8("://images/redStone24.png")));
    }
    m_serialPortTextIndicator->setText( m_serialPort->portName() );
}

void MainWindow::closeSerialPort()
{
    m_serialPort->close();
    m_console->setEnabled(false);
    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
    ui->actionConfigure->setEnabled(true);
    ui->statusBar->showMessage( tr("Disconnected") );
    m_serialPortTextIndicator->setText( m_serialPort->portName() );
    m_serialPortGraphicIndicator->setPixmap(QPixmap(QString::fromUtf8("://images/yellowStone24.png")));
}

void MainWindow::about()
{
    /*
    QMessageBox::about(this, tr("About VisualTerm"),
                       tr("A multiplatform visual terminal<br>(c)2012, 2013 E. Barragan ernestus#(at)#gmail#(dot)#com, GPL 3"));
                       */
    QScopedPointer<AboutDialog> about( new AboutDialog(this) ) ;
    about->exec() ;
}

void MainWindow::writeData(const QByteArray &data)
{
    m_serialPort->write(data);
}

void MainWindow::readSerialData()
{
    /* for different color streams this would use
       something like a PortColor enumeration,
       i.e. green */
    QByteArray data = m_serialPort->readAll() ;
    //m_console->setColor(portColor) ;
    m_console->displayDataFromPort(data) ;
}

void MainWindow::handleError(QSerialPort::SerialPortError error)
{
    if (error == QSerialPort::ResourceError) {
        QMessageBox::critical(this, tr("Critical Error"), m_serialPort->errorString());
        closeSerialPort();
    }
}

void MainWindow::initActionsConnections()
{
    connect( ui->actionConnect, SIGNAL(triggered()), this, SLOT(openSerialPort()) );
    connect( ui->actionDisconnect, SIGNAL(triggered()), this, SLOT(closeSerialPort()) );
    connect( ui->actionQuit, SIGNAL(triggered()), this, SLOT(close()) );
    connect( ui->actionConfigure, SIGNAL(triggered()), m_settingsDialog, SLOT(show()) );
    connect( ui->actionClear, SIGNAL(triggered()), m_console, SLOT(clear()) );
    connect( ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()) );
    connect( ui->actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()) );
}

void MainWindow::on_actionFont_triggered()
{
    //console->setFont( QFontDialog::getFont( 0, console->font()) );
    //well let's give the ability of only showing monospaced fonts,
    //the built in dialog doesn't offer that possibility
    QScopedPointer<FontChooser> fontChooser(new FontChooser( this )) ;
    fontChooser->setCurrentFont( m_console->font() ) ;
    if ( QDialog::Accepted == fontChooser->exec() )
    {
        m_console->setFont( fontChooser->currentFont() ) ;
    }
    m_console->setFocus() ;
}

void MainWindow::on_actionInputInteger_triggered()
{
    if( QDialog::Accepted == m_numericInputDialog->exec() )
    {
        QByteArray ba  = m_numericInputDialog->value() ;
        Q_ASSERT( 0 < ba.count() ) ;
        m_console->displayDataFromUi( ba ) ;
    }
    m_console->setFocus() ;
}

void MainWindow::on_actionHexMode_triggered(bool checked)
{
    m_console->setHexModeEnabled( checked );
    m_console->setFocus() ;
}

void MainWindow::on_action_Create_Byte_Sequence_triggered()
{
    QScopedPointer<SequencesEditor> editor( new SequencesEditor ) ;
    editor->exec() ;
}
